/*
 * Copyright (c) 2025.  little3201.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *       https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.leafage.exploiter.service.impl;

import io.leafage.exploiter.domain.Connection;
import io.leafage.exploiter.dto.ConnectionDTO;
import io.leafage.exploiter.repository.ConnectionRepository;
import io.leafage.exploiter.service.ConnectionService;
import io.leafage.exploiter.service.DBService;
import io.leafage.exploiter.vo.ConnectionVO;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.Collections;
import java.util.List;

@Service
public class ConnectionServiceImpl implements ConnectionService {

    private final ConnectionRepository ConnectionRepository;
    private final DBService dbService;

    public ConnectionServiceImpl(ConnectionRepository ConnectionRepository, DBService dbService) {
        this.ConnectionRepository = ConnectionRepository;
        this.dbService = dbService;
    }

    @Override
    public Page<ConnectionVO> retrieve(int page, int size, String sortBy, boolean descending, String name) {
        Pageable pageable = pageable(page, size, sortBy, descending);

        if (StringUtils.hasText(name)) {
            return ConnectionRepository.findAllByNameContaining(name, pageable)
                    .map(Connection -> convertToVO(Connection, ConnectionVO.class));
        }
        return ConnectionRepository.findAll(pageable)
                .map(Connection -> convertToVO(Connection, ConnectionVO.class));
    }

    @Override
    public List<ConnectionVO> retrieve(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return ConnectionRepository.findAll().stream()
                    .map(Connection -> convertToVO(Connection, ConnectionVO.class)).toList();
        } else {
            return ConnectionRepository.findAllById(ids).stream()
                    .map(Connection -> convertToVO(Connection, ConnectionVO.class)).toList();
        }
    }

    @Override
    public ConnectionVO fetch(Long id) {
        return ConnectionRepository.findById(id).map(Connection -> convertToVO(Connection, ConnectionVO.class)).orElse(null);
    }

    @Override
    public List<String> tables(Long id) {
        return ConnectionRepository.findById(id).map(Connection ->
                        dbService.findAllTables(Connection.getHost(), Connection.getPort(),
                                Connection.getName(), Connection.getUsername(), Connection.getPassword()))
                .orElse(Collections.emptyList());
    }

    @Override
    public ConnectionVO create(ConnectionDTO dto) {
        Connection Connection = convertToDomain(dto, Connection.class);
        Connection = ConnectionRepository.save(Connection);
        return convertToVO(Connection, ConnectionVO.class);
    }

    @Override
    public ConnectionVO modify(Long id, ConnectionDTO dto) {
        Assert.notNull(id, "id must not be null.");

        return ConnectionRepository.findById(id)
                .map(existing -> {
                    Connection Connection = convert(dto, existing);
                    Connection = ConnectionRepository.save(Connection);
                    return convertToVO(Connection, ConnectionVO.class);
                })
                .orElseThrow();
    }

    @Override
    public void remove(Long id) {
        ConnectionRepository.deleteById(id);
    }
}
